package cn.liutao.auth.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.liutao.auth.entity.param.ExchangeParam;
import cn.liutao.auth.entity.param.PayPwdParam;
import cn.liutao.auth.entity.param.PwdParam;
import cn.liutao.auth.entity.param.RestPwdParam;
import cn.liutao.auth.entity.po.User;
import cn.liutao.auth.mapper.UserMapper;
import cn.liutao.common.enums.CommonEnum;
import cn.liutao.common.exception.BadRequestException;
import cn.liutao.common.exception.OrderException;
import cn.liutao.common.utils.RedisUtils;
import cn.liutao.common.utils.ServletUtils;
import cn.liutao.order.entity.po.PayBill;
import cn.liutao.order.entity.vo.AlipayVo;
import cn.liutao.order.service.PayService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;

import static cn.liutao.auth.entity.po.table.UserTableDef.USER;

/**
 * @author liutao
 * @Description 用户管理业务层
 * @date 2023/11/1 8:29
 * @Version 1.0
 */
@Slf4j
public class UserService {

    private static volatile UserService instance;
    private UserMapper userMapper;
    private AuthService authService;
    private PayService payService;

    //私有构造方法
    private UserService(){
        userMapper = ServletUtils.getMapper(UserMapper.class);
        authService = AuthService.getInstance();
        payService = PayService.getInstance();
    }


    /**
     * 双重检查锁实现单例
     * @return
     */
    public static UserService getInstance(){
        if (instance==null){
            synchronized (UserService.class){
                if (instance==null){
                    instance = new UserService();
                }
            }
        }
        return instance;
    }

    /**
     * 获取用户列表
     * @param queryParam
     * @return
     */
    public Page<User> selectList(User queryParam) {
        Page<User> paginate = userMapper.paginate(queryParam.getPageNum(), queryParam.getPageSize(),
                QueryWrapper.create()
                        .where(USER.IS_ADMIN.eq(queryParam.getIsAdmin()))
                        .where(USER.USERNAME.like(queryParam.getUsername()))
                        .where(USER.NICK_NAME.like(queryParam.getNickName()))
        );
        return paginate;
    }

    /**
     * 修改用户信息
     * @param editParam
     */
    public void updateById(User editParam) {
        if (StrUtil.isNotBlank(editParam.getPassword())){
            editParam.setPassword(SecureUtil.md5(editParam.getPassword()));
        }
        userMapper.update(editParam);
        updateRedisUserINfo(editParam.getId());
    }

    /**
     * 删除用户信息
     * @param id
     */
    public void removeById(Integer id) {
        removeRedisUserInfo(id);
        userMapper.deleteById(id);
    }

    /**
     * 重置密码
     * @param restPwdParam
     */
    public void resetPassword(RestPwdParam restPwdParam) {
        User user = new User();
        user.setId(restPwdParam.getUserId());
        user.setPassword(SecureUtil.md5(restPwdParam.getNewPassword()));
        userMapper.update(user);
        removeRedisUserInfo(user.getId());
    }

    /**
     * 新增用户
     * @param addParam
     */
    public void insert(User addParam) {
        User user = userMapper.selectOneByQuery(QueryWrapper.create().where(USER.USERNAME.eq(addParam.getUsername())));
        if (ObjectUtil.isNotNull(user)){
            throw new OrderException("该用户名为【"+user.getUsername()+"】的用户已存在");
        }
        User userDB = new User();
        BeanUtil.copyProperties(addParam,userDB,"balance","id","password");
        addParam.setPassword(SecureUtil.md5(addParam.getPassword()));
        userMapper.insert(addParam);
    }

    /**
     * 更新用户缓存在redis 中的数据
     * @param userId
     */
    private void updateRedisUserINfo(Integer userId){
        User user = userMapper.selectOneById(userId);
        if (user!=null){
            //获取该用户最新保存的token
            String token = RedisUtils.get(CommonEnum.LOGIN_KEY.getValue() + user.getUsername());
            if (StrUtil.isNotBlank(token)){
                //获取redis 缓存中的数据
                User userInfo = RedisUtils.get(CommonEnum.LOGIN_KEY.getValue() + token, User.class);
                if (userInfo!=null){
                    //更新最新的用户信息
                    RedisUtils.set(CommonEnum.LOGIN_KEY.getValue()+token,user);
                    log.info("更新了redis中用户：【{}】的最新数据",user.getNickName());
                }
            }

        }
    }

    /**
     * 删除用户缓存在redis 中的数据
     * @param userId
     */
    private void removeRedisUserInfo(Integer userId){
        User user = userMapper.selectOneById(userId);
        if (user!=null){
            //获取该用户最新保存的token
            String token = RedisUtils.get(CommonEnum.LOGIN_KEY.getValue() + user.getUsername());
            if (StrUtil.isNotBlank(token)){
                //获取redis 缓存中的数据
                User userInfo = RedisUtils.get(CommonEnum.LOGIN_KEY.getValue() + token, User.class);
                if (userInfo!=null){
                   RedisUtils.remove(CommonEnum.LOGIN_KEY.getValue() + token);
                   RedisUtils.remove(CommonEnum.LOGIN_KEY.getValue()+user.getUsername());
                    log.info("删除了redis中用户：【{}】的最新数据",user.getNickName());
                }
            }

        }
    }

    /**
     * 修改密码
     *
     * @param pwdParam
     * @param userId
     */
    public void updatePassword(PwdParam pwdParam, Integer userId) {
        if (!pwdParam.getOldPassword().equals(pwdParam.getOldPasswordAgain())){
            throw new OrderException("两次输入的密码不一致");
        }
        User user = userMapper.selectOneById(userId);
        if (!SecureUtil.md5(pwdParam.getOldPassword()).equals(user.getPassword())){
            throw new OrderException("旧密码错误");
        }
        user.setPassword(SecureUtil.md5(pwdParam.getNewPassword()));
        userMapper.update(user);
        removeRedisUserInfo(user.getId());
    }

    /**
     * 设置支付密码
     * @param userId
     * @param payPwdParam
     */
    public void setPayPwd(Integer userId, PayPwdParam payPwdParam) {
        if (!payPwdParam.getPayPassword().equals(payPwdParam.getPayPasswordAgain())){
            throw new OrderException("两次输出的支付密码不正确");
        }

        User user = userMapper.selectOneById(userId);
        if (user==null){
            throw new OrderException("用户信息不存在");
        }
        if (!SecureUtil.md5(payPwdParam.getPassword()).equals(user.getPassword())){
            throw new BadRequestException("账号密码输入错误");
        }
        //这个接口只有在用户的支付密码为空时才可修改支付密码
        if (StrUtil.isBlank(user.getPayPassword())){
            user.setPayPassword(SecureUtil.md5(payPwdParam.getPayPassword()));
        }

        userMapper.update(user);
    }

    /**
     * 修改支付密码
     * @param userId
     * @param payPwdParam
     */
    public void updatePayPwd(Integer userId, PayPwdParam payPwdParam) {
        if (!payPwdParam.getPayPassword().equals(payPwdParam.getPayPasswordAgain())){
            throw new OrderException("两次输出的支付密码不正确");
        }
        User user = userMapper.selectOneById(userId);
        if (user==null){
            throw new OrderException("用户信息不存在");
        }
        if (!SecureUtil.md5(payPwdParam.getPassword()).equals(user.getPassword())){
            throw new BadRequestException("账号密码输入错误");
        }
        user.setPayPassword(SecureUtil.md5(payPwdParam.getPayPassword()));
        userMapper.update(user);
    }

    /**
     * 校验是否保存支付密码
     * @param userId
     */
    public boolean checkPayPwd(Integer userId) {
        User user = userMapper.selectOneById(userId);
        if (user!=null &&StrUtil.isNotBlank(user.getPayPassword())){
            return true;
        }
        return false;
    }

    /**
     * 充值接口
     *
     * @param userId
     * @param exchangeParam 参数
     */
    public void exchange(Integer userId, ExchangeParam exchangeParam) {
        Integer destination = exchangeParam.getUserId();
        User user = userMapper.selectOneById(destination);
        if (user==null){
            throw new OrderException("要充值的目标用户不存在");
        }
        //校验密码
        boolean verify = authService.verifyPassword(userId, exchangeParam.getPassword());
        if (!verify){
            throw new BadRequestException("密码错误");
        }
        //充值
        BigDecimal balance = user.getBalance() == null ? BigDecimal.ZERO : user.getBalance();
        BigDecimal amount = exchangeParam.getAmount() == null ? BigDecimal.ZERO : exchangeParam.getAmount();
        balance = balance.add(amount);
        user.setBalance(balance);
        userMapper.update(user);
        log.info("充值成功。用户：{}，金额：{}，当前用户余额：{}",user.getNickName(),amount,balance);
    }

    public User getById(Integer userId) {
        return userMapper.selectOneById(userId);
    }

    public AlipayVo exchangeByAlipay(Integer userId, BigDecimal amount) {
        User user = userMapper.selectOneById(userId);
        if (user==null){
            throw new OrderException("要充值的目标用户不存在");
        }
        PayBill payBill = payService.saveExchangePayBill(userId,amount);
        String payNo = payBill.getPayNo();
        AlipayVo alipayVo = payService.alipay(payNo);
        return alipayVo;
    }
}
